# -*- coding;utf-8 -*-
"""
File name : WriteQuestionList2Tex.py.PY
Program IDE : PyCharm
Create file time: 2025/1/2 11:09
File Create By Author : 朱清闯
"""
import requests
from jinja2 import Template
import os
from django.conf import settings
import re
from html.parser import HTMLParser
from utils import FileOperate, ZipOperate


# 把一般的html符号转换成实际符号
def convert_html_tags_to_latex(content_str):
    pattern_list = [(r'&lt;', '<'),
                    (r'&gt;', '>'),
                    (r'&amp;', '&'),
                    (r'&quot;', r'”'),
                    (r'&times;', '×'),
                    (r'&divide;', '÷'),
                    (r'</p><p>', r' \\newline '),
                    (r'><p>', r'> \\newline '),
                    (r'<p>', r''),
                    (r'</p>', r' \\newline '),
                    ]
    for item in pattern_list:
        content_str = re.sub(item[0], item[1], content_str)
    return content_str


# 从html表格中提取内容，返回二维数组
class TableParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.in_table = False
        self.in_tr = False
        self.in_td = False
        self.in_th = False
        self.rows = []
        self.current_row = []
        self.current_data = ''

    def handle_starttag(self, tag, attrs):
        if tag == 'table':
            self.in_table = True
        elif tag == 'tr' and self.in_table:
            self.in_tr = True
            # 开始新的行时，如果当前行有数据，则将其添加到rows中
            if self.current_row:
                self.rows.append(self.current_row)
                self.current_row = []
        elif (tag == 'td' or tag == 'th') and self.in_tr:
            self.in_td = True

    def handle_endtag(self, tag):
        if tag == 'table':
            self.in_table = False
        elif tag == 'tr':
            self.in_tr = False
            # 结束行时，将当前行添加到rows中
            if self.current_row:
                self.rows.append(self.current_row)
                self.current_row = []
        elif tag == 'td' or tag == 'th':
            self.in_td = False
            self.in_th = False
            # 结束单元格时，将当前数据添加到当前行中
            if self.current_data.strip():
                self.current_row.append(self.current_data.strip())
            self.current_data = ''

    def handle_data(self, data):
        if self.in_td:
            self.current_data += data


# def extract_table_data(html):
#     parser = TableParser()
#     parser.feed(html)
#     return parser.rows
# 以<tr></tr>标签内数据为行，提取到数组中
def extract_table_data(html):
    rows = html.split('<tr>')
    data = []
    for row in rows[1:]:
        if '<td>' in row:
            cells = row.split('<td>')[1:]
        else:
            cells = row.split('<th>')[1:]
        row_data = []
        for cell in cells:
            if '</td>' in cell:
                content = cell.split('</td>')[0]
            else:
                content = cell.split('</th>')[0]
            row_data.append(content)
        data.append(row_data)
    return data


# 把表格转行成latex格式
def table_to_latex(string: str):
    if 'table' not in string:
        return string
    table_data = extract_table_data(string)
    print('二维数组的表格', table_data)
    table_latex = r' \begin{tabular} ' + '{' + '|c'*len(table_data[0]) + '|}' + ' \\hline '
    for row_item in table_data:
        for col_index in range(len(row_item)):
            col_item = row_item[col_index]
            if col_index < len(row_item) - 1:
                table_latex += col_item + ' & '
            else:
                table_latex += col_item + ' \\\\ '
        table_latex += ' \\hline '
    table_latex += ' \end{tabular} \\\\ '
    print('转换后的latex表格：', table_latex)
    return table_latex


# 把图片转行成latex格式
def convert_table_tags_to_latex(string: str):
    i = 0
    match = re.search(r'<table.*?</table>', string[i:])
    i = string.find(r'<table')
    while match:
        table_str = match.group(0)
        table_latex = table_to_latex(string=table_str)
        string = string[:i] + table_latex + string[i+len(table_str):]
        i = string.find(r'<table')
        match = re.search(r'<table.*?</table>', string[i:])
    return string


# 把图片转行成latex格式
def convert_image_tags_to_latex(string: str, question_type=1):
    i = 0
    match_static = re.search(r'/static/images/(.*?)\"', string[i:])
    match_img = re.search(r'<img.*?>', string[i:])
    i = string.find(r'<img')
    while match_static:
        # 先将图片复制到临时文件夹
        image_name = match_static.group(1)
        source_image = os.path.join(settings.BASE_DIR).replace('\\', '/') + f'/static/images/{image_name}'
        destination_folder = os.path.join(settings.BASE_DIR).replace('\\', '/') + '/static/temp/tex/images/'
        error_image = os.path.join(settings.BASE_DIR).replace('\\', '/') + '/static/images/error.jpg'
        if not os.path.exists(source_image):
            FileOperate.copy_rename_file(source_file=error_image,
                                         destination_folder=destination_folder,
                                         new_file_name=image_name)
        else:
            FileOperate.copy_file(source_file=source_image, destination_folder=destination_folder)
        if question_type == 3:
            # 非选择题保持原图片大小
            graphic_string = r'\includegraphics{' + image_name + r'}'
        elif question_type == 2:
            # 填空题
            if 'width' in string[i:]:
                width_value = re.search(r'width="(.*?)"', string[i:])
                if width_value:
                    width_value = width_value.group(1)
                    width_cm = int(width_value) // 28
                    graphic_string = r'\includegraphics[width=' + str(width_cm) + 'cm]{' + image_name + r'}'
            else:
                graphic_string = r'\includegraphics[width=5cm]{' + image_name + r'}'
        elif question_type == 1:
            # 如果有指定width，则按照width转换，即除以28
            # 选项内的图片控制在宽度1.5cm，非选项内，控制3cm
            if 'width' in string[i:]:
                width_value = re.search(r'width="(.*?)"', string[i:])
                if width_value:
                    width_value = width_value.group(1)
                    width_cm = int(width_value) // 28
                    graphic_string = r'\includegraphics[width=' + str(width_cm) + 'cm]{' + image_name + r'}'
            elif 'A.' in string[i-5:i] or 'B.' in string[i-5:i] or 'C.' in string[i-5:i] or 'D.' in string[i-5:i]:
                graphic_string = r'\includegraphics[width=1.5cm]{' + image_name + r'}'
            else:
                graphic_string = r'\includegraphics[width=5cm]{' + image_name + r'}'
        else:
            # 其他题型保持不变
            graphic_string = r'\includegraphics{' + image_name + r'}'
        string = string[:i] + graphic_string + string[i+len(match_img.group(0)):]
        i = string.find(r'<img')
        match_img = re.search(r'<img.*?>', string[i:])
        match_static = re.search(r'/static/images/(.*?)\"', string[i:])
    return string


def replace_placeholder_in_tex(paper_information: dict, question_list: list, liti_list: list, lianxi_list: list):
    data = {'zsd': paper_information['zsd'], 'paper_title': paper_information['title'], 'question_list': question_list,
            'liti_list': liti_list, 'lianxi_list': lianxi_list}
    file_path = os.path.join(settings.BASE_DIR).replace('\\', '/') + "/static/temp/templates/template_exercise.tex"
    if paper_information['usage_type'] == 'examination':
        file_path = os.path.join(settings.BASE_DIR).replace('\\', '/') + "/static/temp/templates/template_examination" \
                                                                         ".tex "
    elif paper_information['usage_type'] == 'guidepaper':
        file_path = os.path.join(settings.BASE_DIR).replace('\\',
                                                            '/') + "/static/temp/templates/template_guidepaper.tex"
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()
    template = Template(content)
    new_content = template.render(data)
    file_path_new = os.path.join(settings.BASE_DIR).replace('\\', '/') + '/static/temp/tex/a.tex'
    with open(file_path_new, 'w', encoding='utf-8') as file:
        file.write(new_content)
    print("占位符已成功替换。")


def deal_tail_newline_and_convert_image_table(question_list):
    for i in range(len(question_list)):
        question_list[i]['content'] = convert_html_tags_to_latex(question_list[i]['content'])
        len_newline = -len('\\newline')
        if 'newline' in question_list[i]['content'].strip()[-10:]:
            # print(f'第{i}个content尾部含有换行')
            question_list[i]['content'] = question_list[i]['content'].strip()[:len_newline]
        question_list[i]['answer'] = convert_html_tags_to_latex(question_list[i]['answer'])
        if 'newline' in question_list[i]['answer'].strip()[-10:]:
            question_list[i]['answer'] = question_list[i]['answer'].strip()[:len_newline]
        question_list[i]['explain'] = convert_html_tags_to_latex(question_list[i]['explain'])
        if 'newline' in question_list[i]['explain'].strip()[-10:]:
            question_list[i]['explain'] = question_list[i]['explain'].strip()[:len_newline]
        question_list[i]['content'] = convert_image_tags_to_latex(question_list[i]['content'])
        question_list[i]['answer'] = convert_image_tags_to_latex(question_list[i]['answer'])
        question_list[i]['explain'] = convert_image_tags_to_latex(question_list[i]['explain'])
        question_list[i]['content'] = convert_table_tags_to_latex(question_list[i]['content'])
        question_list[i]['answer'] = convert_table_tags_to_latex(question_list[i]['answer'])
        question_list[i]['explain'] = convert_table_tags_to_latex(question_list[i]['explain'])
    print('转换成tex后的question_list内容：', question_list)
    return question_list


def write_questions_2_tex(paper_information=None, question_list=None):
    print('进入tex渲染, 原始试题:', question_list)
    # 把html元素转换成latex格式，去掉尾部的换行符newline
    if paper_information is None:
        paper_information = {'title': '浙江省信息技术选考模拟', 'answer_position': 'detach', 'type_sorted': False,
                             'return_file_type': 'pdf', 'usage_type': 'exercise', 'liti_list': [], 'lianxi_list': []}
    liti_list = paper_information['liti_list']
    lianxi_list = paper_information['lianxi_list']
    # 练习卷和测试卷都用question_list数组，进行转换处理
    if paper_information['usage_type'] in ['exercise', 'examination']:
        question_list = deal_tail_newline_and_convert_image_table(question_list)
    # 练习卷和测试卷都用question_list数组，进行转换处理
    else:
        liti_list = deal_tail_newline_and_convert_image_table(paper_information['liti_list'])
        lianxi_list = deal_tail_newline_and_convert_image_table(paper_information['lianxi_list'])
    # 把试题和试卷信息写入文件a.tex，利用jinja2写入模板得到a.tex
    replace_placeholder_in_tex(paper_information=paper_information, question_list=question_list, liti_list=liti_list,
                               lianxi_list=lianxi_list)
    # 读取a.tex 和用到的图片images文件夹，打包成zip，并以文件流的形式把zip文件给flask端
    tex_file_path = os.path.join(settings.BASE_DIR).replace('\\', '/') + "/static/temp/tex/a.tex"
    if not os.path.exists(tex_file_path):
        print('/static/temp/tex/a.tex不存在')
        return 'error'

    # 以下请求flask端后，接收 a.pdf 文件流并保存到/static/temp/tex/目录下
    extension = paper_information['return_file_type']
    return_file_path = os.path.join(settings.BASE_DIR).replace('\\', '/') + f"/static/temp/tex/a.{extension}"
    if extension == 'tex':
        return f"/static/temp/tex/a.tex"
    # 把tex、sty文件和文件夹images打包成zip格式
    # 先删除/static/temp/tex/目录下的所有.zip文件和.pdf文件
    folder = os.path.join(settings.BASE_DIR).replace('\\', '/') + "/static/temp/tex"
    FileOperate.delete_file_by_extension(folder=folder,extension_name='.pdf')
    FileOperate.delete_file_by_extension(folder=folder, extension_name='.zip')
    zip_file_path = ZipOperate.compress_folder_zip(folder_to_compress=folder)
    if zip_file_path == 'error':
        return 'error'
    with open(zip_file_path, 'rb') as zip_file:
        zip_file_content = zip_file.read()
        url = "http://117.72.37.184:7000/zip2pdf"
        headers = {'Content-Type': 'application/octet-stream', 'Return-File-Type': 'pdf',
                   'File-Type': 'zip'}
        response = requests.post(url, data=zip_file_content, headers=headers)
        print('收到flask端发来的结果：', response)
        if response.status_code == 200:
            # 以文件流形式发送给前端
            with open(return_file_path, 'wb') as pdf_file:
                pdf_file.write(response.content)
            return f"/static/temp/tex/a.{extension}"
        return 'error'
